#include "mycachedata.h"

#include "receivedata.h"
#include "config/configread.h"

#include <QFile>
#include <QDateTime>
#include <QDebug>

//static data
qreal  MyCacheData::FLIMIT = qreal(0.0000001);
MyCacheData* MyCacheData::instance = NULL;
//
MyCacheData* MyCacheData::getInstance()
{
    if (NULL == MyCacheData::instance)
    {
        MyCacheData::instance = new MyCacheData();
    }
    return MyCacheData::instance;
}

void MyCacheData::Destroy()
{
    if (NULL != MyCacheData::instance) {
        delete MyCacheData::instance;
        MyCacheData::instance = NULL;
    }
}

MyCacheData::~MyCacheData()
{

}

void MyCacheData::init()
{
#ifdef ANDROID
    QString confPath = "/storage/emulated/0/GatherControl/appconf.xml";
    QFile conffile(confPath);
    if(!conffile.exists()){
        qWarning() << QString("conf:%1 is not exist!").arg(confPath);
        confPath = "appconf.xml";
    }
 #else
    QString confPath = "appconf.xml";
#endif
    XMLRead::readAppConf(appConf,confPath);
    qInfo() << QString("load %1 finish!").arg(confPath);
    XMLRead::readDevs(mydevs,ids, appConf.devPath);
    devs_mutex =  new QMutex(QMutex::Recursive);
    qInfo() << QString("load %1 finish!").arg(appConf.devPath);
    XMLRead::readPMaps(pmapsDev, ids, appConf.pmapPath);
    qInfo() << QString("load %1 finish!").arg(appConf.pmapPath);
    //point from gather to dev ponit
    for (QList<PMapDev>::iterator it = pmapsDev.begin(); it!=pmapsDev.end();it++)
    {
        ftmapDev.insert(KeyObj_FTDev(it->from.ipStr,it->from.pID,it->from.pType),it->to);
        tfmapDev.insert(KeyObj_TFDev(it->to.devID,it->to.pID), it->from);
    }
    if (ftmapDev.size()!= tfmapDev.size())
    {
        qWarning() << QString("point map config error,the ftmap.size=%1,tfmap=%2"
                            ",please check your config file %3!")
                    .arg(ftmapDev.size()).arg(tfmapDev.size()).arg(appConf.pmapPath);
    }
    XMLRead::readPlans(plans, ids, appConf.planPath);
    qInfo() << QString("load %1 finish!").arg(appConf.planPath);

    XMLRead::readGather(commdef,appConf.gatherPath);
    qInfo() << QString("load %1 finish!").arg(appConf.gatherPath);

    qInfo() <<"commdef.gathers.size()=" << commdef.gathers.size();
    qInfo() <<"commdef.trans.size()=" << commdef.trans.size();
    qInfo() <<"commdef.spdefs.size()=" << commdef.spdefs.size();
    qInfo() <<"commdef.netdefs.size()=" << commdef.netdefs.size();
    qInfo() <<"commdef.protodefs.size()=" << commdef.protodefs.size();

//    emit readLod(QString("read gmap conf_path=").arg(filePath_gmap));
    XMLRead::readGMap(pmaps,appConf.gmapPath);
    qInfo() << QString("load %1 finish!").arg(appConf.gmapPath);
    qInfo() <<"pmaps.size()=" << pmaps.size();
    //gather point to pcs point
    for (QList<PMap>::iterator it = pmaps.begin(); it != pmaps.end(); it++)
    {
        ftmap.insert(KeyObj_FT(it->pfrom.gid,it->pfrom.pid,it->pfrom.ptype), it->pto);
        tfmap.insert(KeyObj_TF(it->pto.ptype,it->pto.pid), it->pfrom);
    }
    if (ftmap.size() != tfmap.size())
    {
        qWarning() << QString("point map config error,the ftmap.size=%1,tfmap=%2"
                            ",please check your config file %3!")
            .arg(ftmap.size()).arg(tfmap.size()).arg(appConf.gmapPath);
    }
    ptr_ReceiveData = ReceiveData::getInstance();
}

bool MyCacheData::getPTO(int _gid, int _pid, PType _ptype, PTo &_pto)
{
    return ftmap.getVal(KeyObj_FT(_gid, _pid, _ptype),_pto);
}

bool MyCacheData::getPFrom(int _pid, PType _ptype, PFrom &pf)
{
    return tfmap.getVal(KeyObj_TF(_ptype,_pid), pf);
}

qint64 MyCacheData::getUsec()
{
    return QDateTime::currentMSecsSinceEpoch();
}

qint64 MyCacheData::getSec()
{
    return QDateTime::currentSecsSinceEpoch();
}

bool MyCacheData::setValue(QString _ipStr, int _id, PType _pType, float _val)
{
//    qInfo() << QString("setValue(1):ip(%1),id(%2),ptype(%3),val(%4)")
//                .arg(_ipStr).arg(_id).arg((int)_pType).arg(_val,0,'f',2);
    bool ret = false;
    PToDev _pto;
    if (ftmapDev.getVal(KeyObj_FTDev(_ipStr,_id,_pType), _pto))
    {
//        qInfo() << QString("setValue(2):ip(%1),id(%2),ptype(%3),val(%4)")
//                    .arg(_ipStr).arg(_id).arg((int)_pType).arg(_val,0,'f',2);
        float _vall = _val;
        bool sendflag = false;
        bool recordflag = false;
        int  clientType = 1;
        ret = setValue(_pto.devID, _pto.pID, _vall, sendflag, recordflag, clientType);
        //
        qint64 _usec = getUsec();
        //client
        if (sendflag)
        {
//            printf("setValue(3):ip(%s),id(%d),ptype(%d),val(%.3f),usec(%ld)\n"
//                   ,_ipStr.toStdString().c_str(),_id,_pType,_val,(long)_usec);
            WDC _wdlc(static_cast<unsigned long long>(_pto.devID), _pto.pID
                , static_cast<unsigned int>(_usec/1000)
                , static_cast<unsigned int>(_usec%1000), _vall, clientType);
            ptr_ReceiveData->addWDLC(_wdlc);
            if(this->getYunFunc()){
                ptr_ReceiveData->addWDYun(_wdlc);
            }
            if (this->getMcsFunc()) {
//                ptr_ReceiveData->addWDLS(_wdlc);
            }
        }

        //record
        if (recordflag)
        {
            //printf("setValue(4):ip(%s),id(%d),ptype(%d),val(%.3f)\n",_ipStr.c_str(),_id,_pType,_val);
//            ptr_ReceiveData->addItem(_pto.devID, _pto.pID
//                , 1000 * static_cast<long long>(time(NULL)) + static_cast<long long>(_usec)
//                , _vall);
        }
    }
    return ret;
};
//set cache data and jude the data's update,record,order and so on.
bool MyCacheData::setValue(unsigned long long _devID, unsigned int _pID
    , float &_val,bool &sendflag, bool &recordflag, int &clientType)
{
    bool ret = false;
    bool valChange = false;     //是否发生值改变
    bool changRecordF = false;  //是否记录
    bool clientOrder = false;   //客户端是否订购

    devs_mutex->lock();
    for (QList<Dev>::iterator it = mydevs.begin(); it != mydevs.end(); it++)
    {
        if (it->devInfo.devID == (long long)_devID)
        {
            for (QList<PInfoDev>::iterator itp = it->pInfo.begin(); itp != it->pInfo.end(); itp++)
            {
                if (itp->pID == _pID)
                {
                    if (OnYX==itp->pType|| OnYXS == itp->pType)
                    {
                        _val = static_cast<float>(_val ? 1 : 0);
                    }
                    else {
                        _val = _val*(itp->ratio) + itp->base;
                    }
                    if (abs(itp->defVal - _val)>FLIMIT)
                    {
                        valChange = true;
                        itp->ValChange = true;
                        itp->markT = getSec() + itp->upLoopTime;
                    }
                    if (itp->markT < getSec())
                    {
                        valChange = true;
                        itp->markT = getSec() + itp->upLoopTime;
                    }
                    changRecordF = itp->changeRecord;
//                    changeUpF = itp->changeUp;
                    itp->defVal= _val;
                    clientOrder = (it->devInfo.clientOrder && itp->clientOrder);
                    clientType = (it->devInfo.clientType&itp->clientType);
                    ret = true;
                    break;
                }
            }
            break;
        }
    }
    devs_mutex->unlock();
    sendflag = (valChange && clientOrder)?true:false;
    recordflag = (changRecordF && valChange)?true:false;
    return ret;
}

QList<Plan> MyCacheData::getPlans()
{
    return plans;
};

bool MyCacheData::getConditionJude(unsigned long long _devID, unsigned int _pID, float rVal, float &_val, bool &_valChange)
{
    bool ret = false;
    try{
        devs_mutex->lock();
        for (QList<Dev>::iterator it = mydevs.begin(); it != mydevs.end(); it++)
        {
            if (it->devInfo.devID == (long long)_devID)
            {
                for (QList<PInfoDev>::iterator itp = it->pInfo.begin(); itp != it->pInfo.end(); itp++)
                {
                    if (itp->pID == _pID)
                    {
                        _val = itp->defVal;
                        _valChange = itp->ValChange;
                        //辅助条件监测,数据变化判定
                        if (itp->ValChange&&abs(itp->defVal - rVal)<FLIMIT)
                        {
                            itp->ValChange = false;
                        }
                        ret = true;
                        break;
                    }
                }
                break;
            }
        }
        devs_mutex->unlock();
    }catch(...){
        qDebug() << QString("MyCacheData::getConditionJude(%1,%2,%3) Exception!")
                    .arg(_devID).arg(_pID).arg(rVal);
    }

    return ret;
};

bool MyCacheData::getFromInfo(unsigned long long _devID, unsigned int _pID,PFromDev &_pfrom)
{
    return tfmapDev.getVal(KeyObj_TFDev(_devID, _pID), _pfrom);
}

bool MyCacheData::getValue(unsigned long long _devID, unsigned int _pID, float &_val)
{
    bool ret = false;
    try{
        devs_mutex->lock();
        for (QList<Dev>::iterator it = mydevs.begin(); it != mydevs.end(); it++)
        {
            if (it->devInfo.devID==(long long)_devID)
            {
                for (QList<PInfoDev>::iterator itp = it->pInfo.begin(); itp!=it->pInfo.end();itp++)
                {
                    if (itp->pID==_pID)
                    {
                        _val = itp->defVal;
                        ret = true;
                        break;
                    }
                }
                break;
            }
        }
        devs_mutex->unlock();
    }catch(...){
        qDebug() << QString("MyCacheData::getValue(%1,%2,%3) Exception!")
                    .arg(_devID).arg(_pID).arg(_val);
    }
    return ret;
}

bool MyCacheData::getCValue(unsigned long long _devID, unsigned int _pID, float &_val)
{
    bool ret = false;
    try{
        devs_mutex->lock();
        for (QList<Dev>::iterator it = mydevs.begin(); it != mydevs.end(); it++)
        {
            if (it->devInfo.devID == (long long)_devID)
            {
                for (QList<PInfoDev>::iterator itp = it->pInfo.begin(); itp != it->pInfo.end(); itp++)
                {
                    if (itp->pID == _pID)
                    {
                        if (abs(itp->ratio) < FLIMIT)
                            _val = _val - itp->base;
                        else
                            _val = (_val-itp->base)/itp->ratio;
                        ret = true;
                        break;
                    }
                }
                break;
            }
        }
        devs_mutex->unlock();
    }catch(...){
        qDebug() << QString("MyCacheData::getCValue(%1,%2,%3) Exception!")
                    .arg(_devID).arg(_pID).arg(_val);
    }

    return ret;
}

QList<DevClient> MyCacheData::getDevInfo()
{
    QList<DevClient> ret;
    try{
        devs_mutex->lock();
        for (QList<Dev>::iterator it = mydevs.begin(); it != mydevs.end(); it++)
        {
            DevClient dcl;
            dcl.devID = it->devInfo.devID;
            dcl.devType = it->devInfo.devType;
            dcl.name = it->devInfo.desc;
            ret.append(dcl);
        }
        devs_mutex->unlock();
    }catch(...){
        qDebug() << QString("MyCacheData::getDevInfo Exception!");
    }

    return ret;
}

QList<PointClient> MyCacheData::getPointInfo(int devID)
{
    QList<PointClient> ret;
    try{
        devs_mutex->lock();
        for (QList<Dev>::iterator it = mydevs.begin(); it != mydevs.end(); it++)
        {
            if (it->devInfo.devID == devID)
            {
                for (QList<PInfoDev>::iterator itp = it->pInfo.begin(); itp != it->pInfo.end(); itp++)
                {
                    PointClient pcl;
                    pcl.pID = itp->pID;
                    pcl.pType = itp->pType;
                    pcl.name = itp->desc;
                    pcl.defval = itp->defVal;
                    ret.append(pcl);
                }
                break;
            }
        }
        devs_mutex->unlock();
    }catch(...){
        qDebug() << QString("MyCacheData::getPointInfo(%1) Exception!").arg(devID);
    }
    return ret;
}


void MyCacheData::TimeUpVirtualPInfo()
{
    qint64 _usec = getUsec();
    qint64 _sec = getSec();
    QQueue<WDC> _wdlcs;
    try{
        QList<Dev>::iterator itdev;
        QList<PInfoDev>::iterator itp;
        if(devs_mutex->tryLock(100)){
        for ( itdev = mydevs.begin(); itdev != mydevs.end(); itdev++)
        {
            for ( itp = itdev->pInfo.begin(); itp != itdev->pInfo.end(); itp++)
            {
                if ((itdev->devInfo.clientOrder && itp->clientOrder)
                        &&(3==itp->pType || 4==itp->pType)
                        &&((itp->markT+10)<_sec))
                {
                    itp->markT = _sec;
                    WDC _wdlc(static_cast<unsigned long long>(itdev->devInfo.devID), itp->pID
                        , static_cast<unsigned int>(_usec/1000)
                        , static_cast<unsigned int>(_usec%1000), itp->defVal
                        , (itdev->devInfo.clientType&itp->clientType));
                    _wdlcs.append(_wdlc);
                }
            }
        }
        devs_mutex->unlock();
        }
    }catch(...){
        qDebug() << "MyCacheData::TimeUpVirtualPInfo Exception!";
    }
    while (!_wdlcs.isEmpty()) {
        WDC _wdlc = _wdlcs.dequeue();
        ptr_ReceiveData->addWDLC(_wdlc);
        if(this->getYunFunc()){
            ptr_ReceiveData->addWDYun(_wdlc);
        }
        if (this->getMcsFunc()) {
//                ptr_ReceiveData->addWDLS(_wdlc);
        }
    }
}
